package lispinterpreter;

import java.util.LinkedList;

public class LispList {

    protected boolean isAtom;

    // Atributos
    public LinkedList<LispList> linkedList;

    public LispList() {
	linkedList = new LinkedList<LispList>();
	this.setAtom(false);
    }

    public void addElement(LispList l) {
	linkedList.add(l);
    }

    public boolean cAtomVerifier() {
	if (this.isAtom) {
	    LispAtom atomo = (LispAtom) this;
	    if (atomo.getType() == LispAtom.ATOM_TYPE_PARENTHESIS) {
		return true;
	    }
	}
	return false;
    }

    public boolean fAtomVerifier() {
	if (this.isAtom) {
	    LispAtom atomo = (LispAtom) this;
	    if (atomo.getType() == LispAtom.ATOM_TYPE_FLOAT) {
		return true;
	    }
	}
	return false;
    }

    public LispList getAndRemoveFirstElement() {
	return linkedList.remove();
    }

    public LispList getElement(int index) {
	return linkedList.get(index);
    }

    public LispList getFirstElement() {
	return linkedList.getFirst();
    }

    public int getSize() {
	return linkedList.size();
    }

    /**
     * Indica la ubicación de la variable en la lista LispList por medio de la
     * posición desde el inicio
     * 
     * @return posición de la variable desde el inicio de la lista.
     */
    public int getVariableLocation() {
	Object arr[] = linkedList.toArray();
	LispAtom lispAtom;
	int index = 0;

	for (int i = 1; i < this.size(); i++) { // Debe ser 1 para quitar el
						// operando
	    lispAtom = (LispAtom) arr[i];
	    if (LispAtom.ATOM_TYPE_STRING == lispAtom.getType()) {
		index = i;
		break;
	    }

	}
	return index;
    }

    public boolean isAtom() {
	return isAtom;
    }

    /**
     * @pre LispList esta formado de atomos, sin operador.
     * @param tipo
     * @return
     */
    public boolean isParameter(int tipo) {
	boolean test = true;
	Object arreglo[] = linkedList.toArray();
	LispAtom lispObject;
	for (int i = 1; i < this.size(); i++) {
	    lispObject = (LispAtom) arreglo[i];
	    test = test && (tipo == lispObject.getType());
	}
	return test;
    }

    public boolean isParsed() {
	Object arreglo[] = linkedList.toArray();
	boolean test = true;
	LispList lispObject = new LispList();

	for (int i = 0; i < arreglo.length; i++) {
	    lispObject = (LispList) arreglo[i];
	    if (lispObject.isAtom) {
		test = test && !lispObject.cAtomVerifier();
	    }
	}
	return test;
    }

    /**
     * Indica si una lista es simple.
     * 
     * @return true sí y sólo si la lista está compuesta sólo por átomos.
     */
    public boolean isSimple() {
	Object arreglo[] = linkedList.toArray();
	boolean test = true;
	LispList lispObject = new LispList();
	for (int i = 0; i < arreglo.length; i++) {
	    lispObject = (LispList) arreglo[i];
	    test = test && (lispObject.isAtom());
	}
	return test;
    }

    public void printLispList() {

	for (int i = 0; i < this.size(); i++) {
	    LispList sublista = this.getElement(i);

	    if (sublista.sAtomVerifier()) {
		LispAtom atomo = (LispAtom) sublista;
		atomo.printAtom();
	    }
	    if (sublista.fAtomVerifier()) {
		LispAtom atomo = (LispAtom) sublista;
		atomo.printAtom();
	    } else {
		sublista.printLispList();
	    }
	}
    }

    public void removeElement(int index) {
	linkedList.remove(index);
    }

    public void replaceElement(int index, LispList obj) {
	linkedList.set(index, obj);
    }

    public boolean sAtomVerifier() {
	if (this.isAtom) {
	    LispAtom atomo = (LispAtom) this;
	    if (atomo.getType() == LispAtom.ATOM_TYPE_STRING
		    || atomo.getType() == LispAtom.ATOM_TYPE_PARENTHESIS) {
		return true;
	    }
	}
	return false;
    }

    public boolean bAtomVerifier() {
	if (this.isAtom) {
	    LispAtom atomo = (LispAtom) this;
	    if (atomo.getType() == LispAtom.ATOM_TYPE_BOOLEAN)
		return true;
	}
	return false;
    }

    public void setAtom(boolean isAtom) {
	this.isAtom = isAtom;
    }

    public int size() {
	return linkedList.size();
    }
}
